package cn.itcast.bos.service.impl;

import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.QueryStringQueryBuilder.Operator;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.itcast.bos.domain.take_delivery.Order;
import cn.itcast.bos.domain.take_delivery.WayBill;
import cn.itcast.bos.index.WayBillIndexRepository;
import cn.itcast.bos.repository.WayBillRepository;
import cn.itcast.bos.service.WayBillService;

@Service
@Transactional
public class WayBillServiceImpl implements WayBillService {

	@Autowired
	private WayBillRepository wayBillRepository;
	@Autowired
	private WayBillIndexRepository wayBillIndexRepository;

	@Override
	public void save(WayBill wayBill) {
		// 先根据运单号查询运单是否存在
		WayBill persistWayBill = wayBillRepository.findByWayBillNum(wayBill.getWayBillNum());
		if (persistWayBill == null) {
			// 说明该运单号不存在
			wayBill.setId(null);// 将id设置为空，确保执行的是新增操作
			wayBill.setSignStatus(1);// 设置为待发货状态
			wayBillRepository.save(wayBill);
			// 创建索引库
			wayBillIndexRepository.save(wayBill);
		} else {
			// 运单已经存在，执行更新操作
			// 运单状态为1，即待发送时才可以修改
			if (persistWayBill.getSignStatus() == 1) {
				try {

					Order order = persistWayBill.getOrder();// 防止wayBill中的order内容为null，复制时会造成persistWayBill数据丢失
					BeanUtils.copyProperties(persistWayBill, wayBill);// 将wayBill中的内容复制到persistWayBill
					persistWayBill.setOrder(order);
					persistWayBill.setSignStatus(1);// 设置为待发货状态
					wayBillIndexRepository.save(persistWayBill);
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				throw new RuntimeException("运单已经发出，无法修改！");
			}

		}

	}

	@Override
	public Page<WayBill> findPageDate(WayBill wayBill, Pageable pageable) {
		// 判断是否输入条件查询

		if (StringUtils.isBlank(wayBill.getWayBillNum()) && StringUtils.isBlank(wayBill.getSendAddress())
				&& StringUtils.isBlank(wayBill.getRecAddress()) && StringUtils.isBlank(wayBill.getSendProNum())
				&& (wayBill.getSignStatus() == null || wayBill.getSignStatus() == 0)) {
			// 如果没有条件查询直接从数据库查询
			return wayBillRepository.findAll(pageable);
		} else {
			// 如果有条件查询则使用索引库查询
			// 组织查询条件
			/**
			 * BoolQueryBuilder：用于连接多个查询条件 must：条件必须成立，类似于sql语句中的and must
			 * not：条件必须不成立，类似于sql语句中的not should：条件可以成立，类似于sql语句中的or
			 */

			BoolQueryBuilder query = new BoolQueryBuilder();
			// 向组合对象添加条件
			if (StringUtils.isNotBlank(wayBill.getWayBillNum())) {
				// 运单号查询
				TermQueryBuilder termQueryBuilder = new TermQueryBuilder("wayBillNum", wayBill.getWayBillNum());
				query.must(termQueryBuilder);
			}
			if (StringUtils.isNotBlank(wayBill.getSendAddress())) {
				// 发货地条件模糊查询
				// 情况1:发货地只输入地址的一部分，可以使用模糊查询
				WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder("sendAddress",
						"*" + wayBill.getSendAddress() + "*");
				// 情况2：发货地输入的是详细地址信息，是多个词条，此时先将词条分词后，每个词条匹配查询
				QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(wayBill.getSendAddress())
						.field("sendAddress").defaultOperator(Operator.AND);
				// 以上两种情况有一种满足即可,使用BoolQueryBuilder
				BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
				boolQueryBuilder.should(wildcardQueryBuilder).should(queryStringQueryBuilder);
				query.must(boolQueryBuilder);
			}
			if (StringUtils.isNotBlank(wayBill.getRecAddress())) {
				// 收货地条件模糊查询
				// 情况1:收货地只输入地址的一部分，可以使用模糊查询
				WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder("recAddress",
						"*" + wayBill.getRecAddress() + "*");
				// 情况2：收货地输入的是详细地址信息，是多个词条，此时先将词条分词后，每个词条匹配查询
				QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(wayBill.getRecAddress())
						.field("recAddress").defaultOperator(Operator.AND);
				// 以上两种情况有一种满足即可,使用BoolQueryBuilder
				BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
				boolQueryBuilder.should(wildcardQueryBuilder).should(queryStringQueryBuilder);
				query.must(boolQueryBuilder);
			}
			if (StringUtils.isNotBlank(wayBill.getSendProNum())) {
				// 速运类型等值查询
				TermQueryBuilder termQueryBuilder = new TermQueryBuilder("sendProNum", wayBill.getSendProNum());
				query.must(termQueryBuilder);
			}
			if (wayBill.getSignStatus() != null && wayBill.getSignStatus() != 0) {
				// 运单状态等值查询
				TermQueryBuilder termQueryBuilder = new TermQueryBuilder("signStatus", wayBill.getSignStatus());
				query.must(termQueryBuilder);
			}

			NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(query);
			nativeSearchQuery.setPageable(pageable);// 分页效果
			return wayBillIndexRepository.search(nativeSearchQuery);
		}

	}

	@Override
	public WayBill findByWayBillNum(String wayBillNum) {
		return wayBillRepository.findByWayBillNum(wayBillNum);
	}

	@Override
	public void syncIndex() {
		// 查询数据库中所有运单信息
		List<WayBill> wayBills = wayBillRepository.findAll();
		// 同步索引库
		wayBillIndexRepository.save(wayBills);
	}

	/** 带有查询条件查询运单信息，生成excel报表 */
	@Override
	public List<WayBill> findWayBills(WayBill wayBill) {
		// 判断是否输入条件查询

		if (StringUtils.isBlank(wayBill.getWayBillNum()) && StringUtils.isBlank(wayBill.getSendAddress())
				&& StringUtils.isBlank(wayBill.getRecAddress()) && StringUtils.isBlank(wayBill.getSendProNum())
				&& (wayBill.getSignStatus() == null || wayBill.getSignStatus() == 0)) {
			// 如果没有条件查询直接从数据库查询
			return wayBillRepository.findAll();
		} else {
			// 如果有条件查询则使用索引库查询
			// 组织查询条件
			/**
			 * BoolQueryBuilder：用于连接多个查询条件 must：条件必须成立，类似于sql语句中的and must
			 * not：条件必须不成立，类似于sql语句中的not should：条件可以成立，类似于sql语句中的or
			 */

			BoolQueryBuilder query = new BoolQueryBuilder();
			// 向组合对象添加条件
			if (StringUtils.isNotBlank(wayBill.getWayBillNum())) {
				// 运单号查询
				TermQueryBuilder termQueryBuilder = new TermQueryBuilder("wayBillNum", wayBill.getWayBillNum());
				query.must(termQueryBuilder);
			}
			if (StringUtils.isNotBlank(wayBill.getSendAddress())) {
				// 发货地条件模糊查询
				// 情况1:发货地只输入地址的一部分，可以使用模糊查询
				WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder("sendAddress",
						"*" + wayBill.getSendAddress() + "*");
				// 情况2：发货地输入的是详细地址信息，是多个词条，此时先将词条分词后，每个词条匹配查询
				QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(wayBill.getSendAddress())
						.field("sendAddress").defaultOperator(Operator.AND);
				// 以上两种情况有一种满足即可,使用BoolQueryBuilder
				BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
				boolQueryBuilder.should(wildcardQueryBuilder).should(queryStringQueryBuilder);
				query.must(boolQueryBuilder);
			}
			if (StringUtils.isNotBlank(wayBill.getRecAddress())) {
				// 收货地条件模糊查询
				// 情况1:收货地只输入地址的一部分，可以使用模糊查询
				WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder("recAddress",
						"*" + wayBill.getRecAddress() + "*");
				// 情况2：收货地输入的是详细地址信息，是多个词条，此时先将词条分词后，每个词条匹配查询
				QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(wayBill.getRecAddress())
						.field("recAddress").defaultOperator(Operator.AND);
				// 以上两种情况有一种满足即可,使用BoolQueryBuilder
				BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
				boolQueryBuilder.should(wildcardQueryBuilder).should(queryStringQueryBuilder);
				query.must(boolQueryBuilder);
			}
			if (StringUtils.isNotBlank(wayBill.getSendProNum())) {
				// 速运类型等值查询
				TermQueryBuilder termQueryBuilder = new TermQueryBuilder("sendProNum", wayBill.getSendProNum());
				query.must(termQueryBuilder);
			}
			if (wayBill.getSignStatus() != null && wayBill.getSignStatus() != 0) {
				// 运单状态等值查询
				TermQueryBuilder termQueryBuilder = new TermQueryBuilder("signStatus", wayBill.getSignStatus());
				query.must(termQueryBuilder);
			}
			
			// ElasticSearch 允许搜索分页查询，最大数据条数10000，0表示只显示第一页
			Pageable pageable = new PageRequest(0, 10000);
			NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(query);
			nativeSearchQuery.setPageable(pageable); // 分页效果
			Page<WayBill> pageData = wayBillIndexRepository.search(nativeSearchQuery);
			return pageData.getContent();
		}
	}

	@Override
	public List<Object[]> findChartWayBill() {
		return wayBillRepository.findChartWayBill();
	}

}
